package jadehs.mdis;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.json.XML;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.MongoURI;
import com.mongodb.util.JSON;

/**
 * Servlet implementation class MDIS_Servlet
 */

public class MdisServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	Mongo m = null;

	/**
	 * Default constructor.
	 */
	public MdisServlet() {
		super();
		// TODO Auto-generated constructor stub
	}

	public void init(ServletConfig config) {
	

	}


	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		if(m == null) {
			try {
				MongoURI muri = new MongoURI(
						"mongodb://mdis:mdis@ds033217.mongolab.com:33217/mdis");
				m = muri.connect();
				if(m.getDB("mdis").isAuthenticated() == false)
					m.getDB("mdis").authenticate("mdis", "mdis".toCharArray());
			} catch (UnknownHostException e) {
				e.printStackTrace();
			} catch (MongoException e) {
				e.printStackTrace();
			}
			
		}
		
		int status = 0;
		PrintWriter out = response.getWriter();

		// Input holen
		String location = "";
		if (request.getParameter("location") == "")
			// keine Location uebergeben, versuche Adresse
			location = getLocationFromAdress("", request.getParameter("city"),
					request.getParameter("zip"));
		else
			location = request.getParameter("location");
		if (location.equals(""))
			status = -1;

		String article = "";
		if (request.getParameter("article") != "")
			article = request.getParameter("article");
		else
			status = -1;

		int distance = 0;
		if (request.getParameter("distance") != "")
			distance = Integer.parseInt(request.getParameter("distance")) * 1000;
		else
			status = -1;

		// Wenn bisher kein Fehler
		if (status == 0) {
			// Handler mit Artikel holen
			DB db = m.getDB("mdis");
			DBCollection coll = db.getCollection("vendors");
			DBObject obj = new BasicDBObject("article.name", article);
			DBCursor cur = coll.find(obj);

			String destinations = "";

			// Handler in Liste speichern und fuer Google vorbereiten
			ArrayList<DBObject> dblist = new ArrayList<DBObject>();
			while (cur.hasNext()) {
				DBObject curobj = cur.next();
				dblist.add(curobj);
				String address = (String) curobj.get("address");
				destinations += URLEncoder.encode(address, "UTF-8") + ","
						+ (String) curobj.get("city") + "|";
			}

			// Google Distance Matrix API abfragen
			URL url = new URL(
					"https://maps.googleapis.com/maps/api/distancematrix/json?origins="
							+ location + "&destinations=" + destinations
							+ "&language=de-DE&units=metric&sensor=true");
			InputStream is = url.openStream();
			BufferedReader in = new BufferedReader(new InputStreamReader(is));
			JSONTokener jt = new JSONTokener(in);
			JSONObject json;
			try {
				json = new JSONObject(jt);
				int curdist;
				JSONObject currentobj;
				// Response verarbeiten und gefiltert nach Distanz in die
				// filteredresults einfuegen
				ArrayList<JSONObject> filteredresults = new ArrayList<JSONObject>();
				for (int i = 0; i < dblist.size(); i++) {
					currentobj = json.getJSONArray("rows").getJSONObject(0)
							.getJSONArray("elements").getJSONObject(i);
					curdist = currentobj.getJSONObject("distance").getInt(
							"value");
					if (curdist <= distance) {
						currentobj.put("index", i);
						filteredresults.add(currentobj);
					}
				}
				if (filteredresults.size() > 0) {
					// Resultate sortieren
					Collections.sort(filteredresults, new MyComparator());

					// Resultate als XML zurueckgeben
					response.setContentType("text/xml");
					out.println("<?xml version=\"1.0\"?>");
					out.println("<ergebnisliste>");
					int pos = 0;
					for (JSONObject jsObject : filteredresults) {
						jsObject.put("position", pos);
						DBObject data = dblist.get(jsObject.getInt("index"));
						JSONObject jsdata = new JSONObject(JSON.serialize(data));
						jsdata.remove("$oid");
						jsdata.remove("_id");
						jsdata.put(
								"location",
								getLocationFromAdress(
										jsdata.getString("address"),
										jsdata.getString("city"),
										String.valueOf(jsdata.getInt("zip"))));
						out.println("<eintrag Nummer=\"" + pos + "\">");
						out.println(XML.toString(jsdata));
						out.println(XML.toString(jsObject));
						out.println("</eintrag>");
						pos++;
					}
					out.print("<currentlocation>");
					out.print(location);
					out.println("</currentlocation>");
					out.println("</ergebnisliste>");
				} else {
					response.setContentType("text/plain");
					out.println("Leider keine Ergebnisse.");
				}

			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				out.println("Fehler in der Datenverarbeitung. Bitte Eingaben pruefen.");
			}
		} else {
			out.println("Fehler in der Datenverarbeitung. Bitte Eingaben pruefen.");
		}

	}

	private String getLocationFromAdress(String street, String city, String zip)
			throws IOException {
		String retVal = "";
		if (city == "" && zip == "")
			retVal = "";
		else {
			// Google Geocoding API anfragen fuer Koordinaten
			URL url = new URL(
					"http://maps.googleapis.com/maps/api/geocode/json?address="
							+ URLEncoder.encode(street, "UTF-8") + "+" + zip
							+ "+" + URLEncoder.encode(city, "UTF-8")
							+ "&sensor=false&region=de");
			InputStream is = url.openStream();
			BufferedReader in = new BufferedReader(new InputStreamReader(is));
			JSONTokener jt = new JSONTokener(in);
			JSONObject json;
			try {
				json = new JSONObject(jt);
				if (json.getString("status").equals("OK")) {
					JSONObject loc = json.getJSONArray("results")
							.getJSONObject(0).getJSONObject("geometry")
							.getJSONObject("location");
					retVal = loc.get("lat") + "," + loc.get("lng");
				}
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return retVal;
	}

	private class MyComparator implements Comparator<JSONObject> {

		@Override
		public int compare(JSONObject o1, JSONObject o2) {
			int retVal = 0;
			try {
				int d1 = o1.getJSONObject("distance").getInt("value");
				int d2 = o2.getJSONObject("distance").getInt("value");
				if (d1 < d2)
					retVal = -1;
				if (d1 == d2)
					retVal = 0;
				if (d1 > d2)
					retVal = 1;
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();

			}
			return retVal;
		}

	}

}
